import {spliceOne} from "./utils/lang";

type EventCallback<T = void> = (args: T) => void;
type EventMap<K, T> = Map<K, Array<EventCallback<T>>>;

export class eventMixin<K = string> {
  events: EventMap<K, any> = new Map();
  constructor() {}

  on(eventName: K, fn: EventCallback) {
    const targetEvents = this.events.get(eventName);
    if (targetEvents) {
      targetEvents.push(fn);
    } else {
      this.events.set(eventName, [fn]);
    }
  }

  off(eventName: K, fn: EventCallback) {
    const targetEvents = this.events.get(eventName);
    if (targetEvents) {
      let count = targetEvents.length
      while (count--) {
        if (targetEvents[count] === fn) {
          spliceOne(targetEvents, count);
        }
      }
    }
  }

  emit<T>(eventName: K, args?: T) {
    // debugger;
    const targetEvents = this.events.get(eventName);
    if (targetEvents) {
      const len = targetEvents.length;
      for (let i = 0; i < len; i++) {
        const fn = targetEvents[i];
        if (fn) {
          fn(args);
        }
      }
    }
  }
}
